﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;

namespace mana.Web.UI.WebControls
{
    public static class GridViewExtensions
    {
        public static void ManageSortingEvent(this GridView grid, GridViewSortEventArgs e)
        {
            if (!grid.AllowSorting)
                return;

            string previousSortExpression = GetSortExpression(grid);

            //  Updates the sort expression
            SetSortExpression(grid, e.SortExpression);

            //  If the sort expression changes the sort direction must be reseted to default
            if (e.SortExpression != previousSortExpression)
                SetSortDirection(grid, SortDirection.Ascending);
            else
            {
                //  If the sort expression is the same as before the sort direction must be inverted
                var sortDirection = GetSortDirection(grid);
                if (sortDirection == SortDirection.Ascending)
                    SetSortDirection(grid, SortDirection.Descending);
                else
                    SetSortDirection(grid, SortDirection.Ascending);
            }

            grid.DataBind();
        }

        public static void ManagePageIndexChangingEvent(this GridView grid, GridViewPageEventArgs e)
        {
            if (!grid.AllowPaging)
                return;

            grid.PageIndex = e.NewPageIndex;
            grid.DataBind();
        }

        public static void ManageDataBindingEvent<T>(this GridView grid)
        {
            Sort<T>(grid);
        }

        #region Sorting & Paging

        #region Constants

        private const string SORT_EXPRESSION_ATTRIBUTE = "sortExpression";
        private const string SORT_DIRECTION_ATTRIBUTE = "sortDirection";

        #endregion Constants

        #region Getters & Setters

        private static string GetSortExpression(GridView grid)
        {
            return GetAttribute(grid, SORT_EXPRESSION_ATTRIBUTE);
        }
        private static void SetSortExpression(GridView grid, string value)
        {
            SetAttribute(grid, SORT_EXPRESSION_ATTRIBUTE, value);
        }

        private static SortDirection GetSortDirection(GridView grid)
        {
            return (SortDirection)(Convert.ToInt32(GetAttribute(grid, SORT_DIRECTION_ATTRIBUTE)));
        }
        private static void SetSortDirection(GridView grid, SortDirection value)
        {
            SetAttribute(grid, SORT_DIRECTION_ATTRIBUTE, Convert.ToString((int)value));
        }

        #endregion Getters & Setters

        private static void Sort<T>(GridView grid)
        {
            if (!grid.AllowSorting)
                return;

            //  If the datasource's type is not List<T>, no sort can be done
            var dsItems = grid.DataSource as List<T>;
            if (dsItems == null)
                return;

            string sortExpression = GetSortExpression(grid);

            //  If there is no sortExpression set, no sort can be done
            if (string.IsNullOrWhiteSpace(sortExpression))
                return;

            SortDirection sortDirection = GetSortDirection(grid);

            Func<T, object> func = p => typeof(T).GetProperty(sortExpression).GetValue(p, null);

            if (sortDirection == SortDirection.Ascending)
                dsItems = dsItems.OrderBy<T, object>(func).ToList();
            else
                dsItems = dsItems.OrderByDescending<T, object>(func).ToList();

            grid.DataSource = dsItems;
        }

        #endregion Sorting & Paging

        #region Utilities

        private static string GetAttribute(GridView grid, string name)
        {
            return grid.Attributes[name];
        }
        private static void SetAttribute(GridView grid, string name, string value)
        {
            if (string.IsNullOrWhiteSpace(GetAttribute(grid, name)))
                grid.Attributes.Add(name, value);
            else
                grid.Attributes[name] = value;
        }

        #endregion Utilities
    }
}
